package org.epidroid.epidroid.androsoul.engine.contacts;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import org.apache.http.ProtocolVersion;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.epidroid.epidroid.androsoul.engine.AndroSoul;
import org.epidroid.epidroid.androsoul.engine.conversation.Conversation;
import org.epidroid.epidroid.androsoul.engine.utils.Visitor;
import org.epidroid.epidroid.utils.Utils;

import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;

/**
 * @author conrath Class that handles a contact (login)
 */
public class NetsoulContact implements Serializable {

	private static final long serialVersionUID = -7952012436490358046L;
	private transient Drawable _image = null;
	private String _name;
	private transient int _id = 1;
	// Locations of the contact
	private transient List<Location> _locations;
	// Time of last location update
	private transient Timestamp _timeUpdateLocation;
	// Conversation that the contacts is having with the user
	private transient Conversation _conversation;
	// State of the user
	private transient String _state = null;
	private transient String _comment = null;

	/*
	 * Link with a phone contact These two ids are useful if one wants to
	 * retrieve the contact's photo in the phone.
	 */
	private Long _phoneContactId = null;
	private Long _phonePhotoId = null;

	/**
	 * Create a contact
	 */
	public NetsoulContact(String name) {
		_locations = new ArrayList<Location>();
		this._name = name;
		_state = "";

		_timeUpdateLocation = new Timestamp(0);
	}

	public void setConversation(Conversation c) {
		_conversation = c;
	}

	/**
	 * Clear the locations of the contact
	 */
	public void clearLocations() {
		_locations.clear();
	}

	/**
	 * Add a location for the contact
	 * 
	 * @param l
	 *            Location to be added
	 */
	public void addLocation(Location l) {
		// prevent locations with same ip
		if (getLocationByIp(l.getIp()) != null)
			return;

		_locations.add(l);

		Calendar calendar = Calendar.getInstance();
		_timeUpdateLocation = new Timestamp(calendar.getTime().getTime());
	}

	public void removeLocation(String ip) {
		Iterator<Location> it = _locations.iterator();
		while (it.hasNext()) {
			Location l = it.next();
			if (l.getIp().equals(ip)) {
				_locations.remove(l);
				return;
			}
		}
	}

	private Location getLocationByIp(String ip) {
		Iterator<Location> it = _locations.iterator();
		while (it.hasNext()) {
			Location l = it.next();
			if (l.getIp().equals(ip)) {
				return l;
			}
		}
		return null;
	}

	@Override
	public String toString() {
		if (_locations.size() > 0) {
			// Location l = locations.get(0);
			// return name + " - " + l.getBestLocation();
			return _name + " (" + _locations.size() + ")";
		} else
			return _name;
	}

	public Drawable getImage(Context c, boolean download_if_needed) {
		if (_image != null)
			return _image;
		try {
			_image = loadImage(c);
			if (_image != null)
				return _image;
			if (download_if_needed && DownloadImage(c))
				return loadImage(c);
			if ((null != _phoneContactId) && (null != _phonePhotoId))
				return new BitmapDrawable(Utils.loadContactPhoto(
						c.getContentResolver(), _phoneContactId, _phonePhotoId));
			return null;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public Drawable loadImage(Context c) {
		try {
			FileInputStream fis = c.openFileInput("img-" + getName());
			_image = Drawable.createFromStream(fis, getName());
			fis.close();
		} catch (Exception e) {
			return null;
		}
		return _image;
	}

	/*
	 * TODO: export as a static method in another module
	 */
	public boolean DownloadImage(Context c) {
		try {
			Log.v(AndroSoul.LOGCAT, "Starting download of " + getName()
					+ "'s picture");
			URL url;

			url = new URL(AndroSoul.PIC_URL + getName());
			InputStream content;
			content = (InputStream) url.getContent();
			FileOutputStream fos;
			fos = c.openFileOutput("img-" + getName(), Context.MODE_PRIVATE);

			int d;
			while ((d = content.read()) != -1) {
				fos.write(d);
			}

			fos.close();

			return true;
		} catch (FileNotFoundException e) {
			Log.e(AndroSoul.LOGCAT,
					"PictureDownloader, FileNotFoundException: "
							+ e.getMessage());
			return false;
		} catch (MalformedURLException e) {
			Log.e(AndroSoul.LOGCAT,
					"PictureDownloader, MalformedURLException: "
							+ e.getMessage());
			return false;
		} catch (IOException e) {
			Log.e(AndroSoul.LOGCAT,
					"PictureDownloader, IOException: " + e.getMessage());
			return false;
		} catch (Exception e) {
			Log.e(AndroSoul.LOGCAT,
					"PictureDownloader, Exception: " + e.getMessage() + " ; "
							+ e.getLocalizedMessage());
			return false;
		}

	}

	public void accept(Visitor v) {
		v.visit(this);
	}

	// / Getters
	public String getName() {
		return _name;
	}

	public Conversation getConversation() {
		return _conversation;
	}

	public Timestamp getTimeUpdateLocation() {
		return _timeUpdateLocation;
	}

	public Iterator<Location> locIterator() {
		return _locations.iterator();
	}

	public List<Location> getLocations() {
		return _locations;
	}

	public String getState() {
		return _state;
	}

	public void setState(String st) {
		_state = st;
	}

	public String getComment() {
		return _comment;
	}

	public void setComment(String _comment) {
		this._comment = _comment;
	}

	public boolean isConnected() {
		return _locations.size() > 0;
	}

	public void setId(int lastContactId) {
		_id = lastContactId;
	}

	public int getId() {
		return _id;
	}

	public Long getPhoneContactId() {
		return _phoneContactId;
	}

	public Long getPhonePhotoId() {
		return _phonePhotoId;
	}

	public void setPhoneContactId(Long long1) {
		_phoneContactId = long1;
	}

	public void setPhonePhotoId(Long long1) {
		_phonePhotoId = long1;
	}

}
